記錄學習內容。看網路上大大們的文章和影片,做些紀錄。
以下內容大多來自網路上大大們的文章。
還不了解,內容可能有錯誤。
MIPS架構
https://zh.wikipedia.org/wiki/MIPS%E6%9E%B6%E6%A7%8B
MIPS(Microprocessor without Interlocked Pipeline Stages),是一種採取精簡指令集(RISC)的指令集架構(ISA)
最早的MIPS架構是 32 位元,最新的版本已經變成 64 位元。商業市場主要競爭對手為ARM與RISC-V。
把 C語言 和MIPS指令集架構 用鍵盤打一遍,當作學習。
計算機組織 Chapter 2.7 Compiling a while loop in C - 朱宗賢老師
https://www.youtube.com/watch?v=5AITP_V7BEs&list=PLylnxZnYW9LbVL5HnYwo7VLmlkhM7lTey&index=13&ab_channel=edwardchu
MIPS 指令集
https://blog.xuite.net/tzeng015/twblog/113272086-MIPS+%E6%8C%87%E4%BB%A4%E9%9B%86
C:
While (save[i] == k)
i +=1
變數對應的暫存器:
i --- > $s3
k --- > $s5
save這個陣列的 地址 -- > $s6
看不懂$s6 是什麼,所以先去看暫存器編號的意思。
$s0 到 $s7 是 暫存器 16號 到23號。存變數用的。
$t0 到 $t7 是 暫存器 8號 到 15號。存temporary variables,存暫時變數用的。
$t0 到 $t7只會在CPU內運算的時候用到。像是我們交換數字,要增加一個tmp變數,才能讓兩數交換。
接著看MIPS 組語 :
Loop : sll $t1, $s3,2 # i 乘 4 後存到$t1暫存器
add $t1, $t1,$s6 # 陣列的初始地址+$t1暫存器 就是save[i] 的地址
lw $to, 0($t1) #save[i] 的memory地址 載到CPU暫存器 $t0
bne $to, $s5,Exit #如果 save[i] 不等於 k ,跳到Exit那一行
addi $s3,$s3,1 # i+=1
j Loop #代表迴圈,會跳到Loop那一行
Exit: #代表迴圈結束,結束程式
sll 2 代表往左移兩位,在最後面加兩個0。
原本是10進位 是 4 ,2進位是100
變成
10進位 是 16 ,2進位是10000
計算機組織 Chapter 2.8 Compiling a C leaf procedure - 朱宗賢老師
https://www.youtube.com/watch?v=AxYTLJiG2v4&list=PLylnxZnYW9LbVL5HnYwo7VLmlkhM7lTey&index=14&ab_channel=edwardchu
這邊講到 funtion 的組語。
int leaf_example (int g,h,i,j)
{
int f ;
f = (g+h) – (i+j);
return f;
}
暫存器變數:
g,h,i,j --- > $a0, $a1, $a2,$a3
f --- > $s0
result --> $v0
$a0 是什麼? 在回到文章的對照表。
$a0 (4號) func的第一個參數
$a1 (5號) func的第二個參數
$a2 (6號) func的第三個參數
$a3 (7號) func的第四個參數
$v0 是什麼?
$v0 (2號) func的 return值
$v1 (3號) func的 return值
接著把組語照打一遍。蠻多行的。
leaf_example:
addi $sp, $sp, -12
sw $t1,8($sp)
sw $t0,4($sp)
sw $s0,0($sp)
add $t0,$a0,$a1
add $t1,$a2,$a3
sub $s0,$t0,$t1
add $v0,$s0,$zero
lw $s0,0($sp)
lw $t0,4($sp)
lw $t1,8($sp)
addi $sp, $sp,12
jr $ra
先看幾個符號:
addi --- >變數 和 常數(-12) 相加
sw -- > 暫存器的東西 放到 記憶體
lw -- > 記憶體的東西 載到 暫存器
$sp 29 stack pointer to the first free location
用來指到記憶體第一個可用的地方 。
$ra 31 return address
用來存 返回地址( return address)
在main裡面 呼叫 func1 ,func1跑完之後,為什麼又可以回到main之後?
因為有存main 的某行 位址 ,才能在回來。
jal label jump to label and save next instruction in $ra
jal 是 ( jump and link ) 。
jr $ra
先跳到 程序起始位址 (? 這個不懂)。
之後會將 下一個指令的位址 ,存到$ra
目前簡單想就是jr 會跳到 某行程式 (某行程式就是下一個指令。某行程式的地址會存到$ra變數)
Main 呼叫 func1 ,所以main是 caller (呼叫者) 。
到func1執行 ,所以func1 稱為 callee(被呼叫者)
接著在回到組語 :
第一行 sp 為何要扣12 ?
因為在這個func 裡面 ,有3個暫存器$t0,$t1,$s0 。只存活在這個func裡?
所以 MIPS 有堆疊Stack ,從上往下的。從高位址 向 低位址 的 。
每個暫存器存的東西就是32個0或1 。 32bit = 4Byte
所以sp -12 的意思 應該是 , 空出 3個暫存器(4Byte*3) 的空間
Sw 就是把 暫存器的東西 放到記憶體 。
所以現在把 $t0,$t1,$s0 放到 堆疊,記憶體 。
$t0,$t1,$s0 加減 運算完後 。
有個$v0 暫存器 , 就是把結果存起來 ,帶到main方法的暫存器。
$v0 2 used to pass values to and from functions
$v1 3 used to pass values to and from functions
最後就是load 把記憶體的東西 載到 暫存器 。
應該是這樣說
如果原本的
$t0 = 1
$t1 = 2
$s0 = 3
經過這個func後,變成
$t0 = 4
$t1 = 5
$s0 = 6
但是我想讓他function結束後還原成原本的:
$t0 = 1
$t1 = 2
$s0 = 3
所以先把123 存到記憶體 。 接著運算後變成$t0 = 4、$t1 = 5、$s0 = 6 。
再分別從記憶體把321載到$s0、$t1、$t0 (因為堆疊是先 排隊的,卻最後排到)
但其實可以寫成這樣:
leaf_example:
addi $sp, $sp, -4
sw $s0,0($sp)
add $t0,$a0,$a1
add $t1,$a2,$a3
sub $s0,$t0,$t1
add $v0,$s0,$zero
lw $s0,0($sp)
addi $sp, $sp,12
jr $ra
因為 有些暫存器 是不用去管 ,要不要復原回123的 。
教學中有個表格:
Zero --- >0 -- > n.a. (不知這是什麼)
$v0-$v1 -- > func 的 return 變數 -- > 不用復原
$a0-$a3 -- >func的參數 -- >不用復原
$to -$t7 -- > 暫時的數 -- >不用復原
$s0 - $s7 -- >變數 -- >要復原
$t8 -$t9 -- >更多暫時的數-- >不用復原
$gp -- >global memory pointer (?目前還不知) -- >要復原
$sp -- > stack pointer to the first free location -- >要復原
$fp -- > frame pointer(?目前還不知) -- >要復原
$ra -- > return address(回到main程式的地址) -- >要復原
所以可以去掉$to -$t7 ,程式就可以少幾行。
計算機組織 Chapter 2.8 Compiling a Recursive C Procedure - 朱宗賢老師
https://www.youtube.com/watch?v=06KE61kXl4w&list=PLylnxZnYW9LbVL5HnYwo7VLmlkhM7lTey&index=15&ab_channel=edwardchu
int fact (int n)
{
If(n<1) return f
else return n*fact(n-1);
}
暫存器:
n -- >$a0
result -- > $v0
組語:
Fact:
addi $sp,$sp,-8 -- >要有兩個暫存器的空間 到記憶體
sw $ra,4($sp) -- > 放$ra -- > 放返回地址(func執行完後要跳回原本的程式的下一行)
sw $a0, 0($sp) -- >放func參數
slti $t0, $a0,1 -- >如果 $a0(func 參數) < 1 ,$t0 =1 ; else $to=0
beq $t0,$zero,L1
addi $vo, $zero,1 -- > n<1 之後的程式-- >return 1啦
addi $sp,$sp,8(準備return ,所以把記憶體stack清掉)
jr $ra -- >結束程式?,只是結束一個funtion,因為遞迴會產生很多funtion (return to caller)!
L1: addi $a0,$a0,-1 -- > 參數-1
jal fact -- >新開一個Fact()了
lw $a0,0($sp) -- >如果新開的Fact()結束了,跳回這,取得a0(func參數)
lw $ra,4($sp) -- >從stack記憶體 寫到 CPU暫存器 -- > $ra(return address)
addi $sp,$sp,8 (準備return ,所以把記憶體stack清掉)
mul $v0,$a0,$v0 --- >n*fact(n-1)
jr $ra
在看一下指令意思:
slti rd rs number if (rs< number ) rd=1;else rd=0
所以 slti $to, $a0,1的意思 是
如果 $a0(func 參數) < 1 ,$t0 =1 ; else $to=0
beq :
beq rs rt label branch to label if (rs==rt)
rs==rt 的話,程式會跳到某一行。
所以 beq $t0,$zero,L1 的意思是:
$t0 是0 的話 ,跳到L1
$t0 是1 的話 ,照常下一行
if (i==j)
f = g + -h
else
f = g -h
f $s0
g $s1
h $s2
i $s3
j $s4
bne $s3,$s4, Else
add $s0,$s1,$s2
j EXIT
Else: sub $s0,$s1,$s2
Exit:
其他:
lui rt number upper halfword of rt = 16-bit number
ori rt rs imm rt = rs OR imm
常數 在放到 暫存器 前 ,可能會做一些處理
lui 是把 number 放到rt 暫存器 ,取前面16bit